#include <iostream>
#include "BTree/BTree.h"
#include "BTree/RegistroDatos.h"
#include "BTreeUtils/TreePrinter.h"
#include "utils/PalabraAleatoria.h"
#include "HashExtensible/HashFile.h"
#include "HashUtils/CargadorFrases.h"


using namespace std;

// Declaraciones
char mostrarMenu(BTree& arbol);
void ejecutarOperacion(char op, BTree& arbol, HashFile &hash);


int main(int argc, char* argv[]){
	try{
		cout << "Entrega del TP-1 (orga-datos) MK-II" << endl;

		BTree arbol;
		HashFile hash;
		char op = '\0';
		do {
			op = mostrarMenu(arbol);
			ejecutarOperacion(op, arbol, hash);

		} while (op != 'x');

		cout << "Programa finalizado." << endl;

		return 0;

	} catch (std::exception& ex){
		cout << "Excepcion: " << ex.what() << endl;
		return 1;
	}
}

//-----------------------------------------------------------------------------


string getNombreArchivo(){
	string nomArch;
	cout << "Ingrese el nombre del archivo: ";
	cin >> nomArch;

	return nomArch;
}


RegistroDatos getTerminoABuscar(){
	string termino;
	cout << "Ingrese el termino que desea buscar en el árbol: ";
	cin >> termino;

	RegistroDatos rd(termino, 0);
	return rd;
}


void mostrarResultado(const RegistroDatos& rd, const RegistroDatos& rBuscar){
	// Chequea el resultado de la busqueda
	if (rd.getClave() == rBuscar.getClave()){
		cout << "Registro encontrado:\n\t" << rd << endl;

	} else {
		cout << "No se encontró el termino '" << rBuscar.getClave() << "' en el árbol" << endl;
	}
}


string getNombreArchivoImpresion(){
	cout << "Seleccione una opción:\n"
		<< "\t[a] - Imprimir en archivo\n"
		<< "\t[c] - Imprimir en pantalla\n" << endl;

	char op = '\0';
	cout << ">> ";
	cin >> op;

	string nomArch = "";
	if (op == 'a'){
		nomArch = getNombreArchivo();
	}

	return nomArch;
}


// Carga el arbol con los datos de un archivo de palabras aleatorias
void cargarArbol(BTree &arbol, string nomArch){
	// TODO: Tener en cuenta que puede venir el archivo sin identificadores
	ifstream fin(nomArch.c_str(), ifstream::in | ifstream::binary);

	while (!fin.eof()){
		PalabraAleatoria p;
		p.cargarPalabra(fin);

		RegistroDatos* reg = new RegistroDatos(p.getPalabra(), fin.tellg());
		arbol.insertarRegistro(reg);
	}

	fin.close();
}


//-----------------------------------------------------------------------------

char mostrarMenu(BTree& arbol){
	cout << "Trabajo practico Nro. 1 de Orga-datos: 'cyber-chamuyo'\n" << endl;

	// TODO: Agregar de abrir un archivo existente (árbol y dispersión)
	// TODO: Agregar eliminar frase por id
	// TODO: Agregar ingresar frase
	// TODO: Agregar modificar una frase
	cout << "Seleccione la operación a realizar:\n"
			<< "\t[c] - Cargar archivo de terminos\n"
			<< "\t[b] - Buscar termino\n"
			<< "\t[i] - Imprimir la estructura del árbol completa\n"
			<< "\t[d] - Imprimir los terminos del árbol\n"
			<< "\t[f] - Cargar archivo de frases\n"
			<< "\t[h] - Buscar frase\n"
			<< "\t[m] - Imprimir frases\n"
			<< "\t[e] - Mostrar estadisticas\n"
			<< "\t[x] - Salir\n" << endl;

	char op;
	cout << ">> ";
	cin >> op;

	return op;
}


void ejecutarOperacion(char op, BTree& arbol, HashFile &hash){

	switch (op){
		case 'c':
			{
				// Carga el árbol con los datos del archivo
				string nomArch = getNombreArchivo();

				arbol.crear("arbolTerminos.bin");
				cargarArbol(arbol, nomArch);
			}
			break;

		case 'b':
			{
				// Realiza las busquedas de terminos en el árbol B+
				RegistroDatos rBuscar = getTerminoABuscar();
				RegistroDatos rd = arbol.buscarRegistro(rBuscar);

				mostrarResultado(rd, rBuscar);
			}
			break;

		case 'i':
			{
				// Imprime todo el contenido del árbol
				string nomArchSalida = getNombreArchivoImpresion();

				TreePrinter printer(arbol);
				printer.ImprimirEnPreOrden(nomArchSalida);
			}
			break;

		case 'd':
			{
				// Imprime solamente los terminos que fueron guardados en el árbol
				string nomArchSalida = getNombreArchivoImpresion();

				TreePrinter printer(arbol);
				printer.ImprimirDatos(nomArchSalida);
			}
			break;

		case 'f':
			{
				// TODO: restaurar la funcionalidad
				// Cargar el archivo de frases
//				string nomArch = getNombreArchivo();
				string nomArch = "frases-utf8.txt";
				cout << "Cargando '" << nomArch << "'" << endl;

				hash.crear("hashFrases.bin");

				CargadorFrases loader(hash);
				loader.cargarFrases(nomArch);
			}
			break;

		case 'h':
			{
				// TODO: Buscar frases
				cout << "\nLa funcionalidad no existe (WIP)" << endl;
			}
			break;

		case 'm':
			{
				// Imprimir frases
				string nomArchSalida = getNombreArchivoImpresion();

				HashPrinter printer(hash);
				printer.ImprimirDatos(nomArchSalida);
			}
			break;

		case 'e':
			{
				// TODO: Componente de estadisticas, este deberá ignorar las stop words
				cout << "\nLa funcionalidad no existe (WIP)" << endl;
			}
			break;

		case 'x':
		default:
			// Nada... creo
			break;
	}
}
